﻿using Crux.Core.SQL.Formatter.Core;

namespace Crux.Core.SQL.Formatter.Language
{
    /// <summary>
    /// 
    /// </summary>
    public class Dialect
    {
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect Db2 = new Dialect(cfg => new Db2Formatter(cfg), "Db2");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect MariaDb = new Dialect(cfg => new MariaDbFormatter(cfg), "MariaDb");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect MySql = new Dialect(cfg => new MySqlFormatter(cfg), "MySql");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect N1ql = new Dialect(cfg => new N1qlFormatter(cfg), "N1ql");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect PlSql = new Dialect(cfg => new PlSqlFormatter(cfg), "PlSql", "pl/sql");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect PostgreSql = new Dialect(cfg => new PostgreSqlFormatter(cfg), "PostgreSql");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect Redshift = new Dialect(cfg => new RedshiftFormatter(cfg), "Redshift");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect SparkSql = new Dialect(cfg => new SparkSqlFormatter(cfg), "SparkSql", "spark");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect StandardSql = new Dialect(cfg => new StandardSqlFormatter(cfg), "StandardSql", "sql");
        /// <summary>
        /// 
        /// </summary>
        public readonly static Dialect TSql = new Dialect(cfg => new TSqlFormatter(cfg), "TSql");

        /// <summary>
        /// 
        /// </summary>
        public static IEnumerable<Dialect> Values
        {
            get
            {
                yield return Db2;
                yield return MariaDb;
                yield return MySql;
                yield return N1ql;
                yield return PlSql;
                yield return PostgreSql;
                yield return Redshift;
                yield return SparkSql;
                yield return StandardSql;
                yield return TSql;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public readonly string name;
        /// <summary>
        /// 
        /// </summary>
        public readonly Func<FormatConfig, AbstractFormatter> func;
        /// <summary>
        /// 
        /// </summary>
        public readonly List<string> aliases;

        /// <summary>
        /// 
        /// </summary>
        private Dialect(Func<FormatConfig, AbstractFormatter> func, string name, params string[] aliases)
        {
            this.func = func;
            this.name = name;
            this.aliases = new List<string>(aliases);
        }

        /// <summary>
        /// 
        /// </summary>
        private bool Matches(string name)
        {
            return string.Equals(name, name, StringComparison.OrdinalIgnoreCase)
                || aliases.Select(s => s.ToLower()).Intersect([name.ToLower()]).Any();
        }

        /// <summary>
        /// 
        /// </summary>
        public static Dialect? NameOf(string name)
        {
            var dialect = Values.Where(d => d.Matches(name)).FirstOrDefault();

            return dialect;
        }
    }
}
